function varargout = TLCustomCodeDlg(action, varargin)

% TL_CUSTOMCODE_DLG manages the user interface for TargetLink Custon Code block
%
% SYNTAX dlgInfo = TLCustomcodeDlg('GetDlgInfo');
%   gets dialog info of TargetLink Constant block
%
%   INPUT ARGUMENTS
%   -/-
%
%   OUTPUT ARGUMENTS
%   dlgInfo     dialog information contains pageNames etc.
%
% SYNTAX [sheetDims, ctrlPos] = TLCustomcodeDlg('CtrlPositions', pageName, commonGeom, dlgInfo, sheetDims);
%   calculates the control positions of all controls of dialog page: <pageName>
%
%   INPUT ARGUMENTS
%   pageName        name of current page
%   commonGeom      common geometry data
%   dlgInfo         dialog information contains pageNames etc.
%   sheetDims       dimension of sheet
%
%   OUTPUT ARGUMENTS
%   sheetDims       modified dimension of sheet
%   ctrlPos         positions of controls
%
% SYNTAX dlgdata = TLCustomcodeDlg('Create', pageName, dlgfig, dlgdata);
%   creates all controls of dialog page: <pageName>
%
%   INPUT ARGUMENTS
%   pageName        name of current page
%   dlgfig          figure handle
%   dlgdata         dialog data
%
%   OUTPUT ARGUMENTS
%   dlgdata         modified dialog data
%
% SYNTAX [dlgdata,bModified] = TLCustomcodeDlg('Manage', pageName, dlgfig, dlgdata, pageAction);
%   manages all actions of dialog page: <pageName>
%
%   INPUT ARGUMENTS
%   pageName        name of current page
%   dlgfig          figure handle
%   dlgdata         dialog data
%   pageAction      modified control of current page
%
%   OUTPUT ARGUMENTS
%   dlgdata         modified dialog data
%   bModified       flag = 1, if dialog data are modified, =0 otherwise
%
% SYNTAX dlgdata = TLCustomcodeDlg('Update', dlgfig, dlgdata, pageNum);
%   updates all controls of dialog page: <pageNum>
%
%   INPUT ARGUMENTS
%   dlgfig          figure handle
%   dlgdata         dialog data
%   pageNum         number of current page
%
%   OUTPUT ARGUMENTS
%   dlgdata         modified dialog data
%
% SYNTAX TLCustomcodeDlg('Apply', dlgfig, dlgdata);
%   writes current blockdata to block and DD
%
%   INPUT ARGUMENTS
%   dlgfig      handle for dialog figure
%   dlgdata     dialog data
%
%   OUTPUT ARGUMENTS
%   - / -


% Author(s): D. Andoleit, T. Pietzsch
% $RCSfile: TLCustomcodeDlg.m $
% $ProjectName: e:/ARC/Components/HostSW/SimulinkBlocksets/TLBlocksets/CommonBlockset/CommonBlockset_SimBlocksUI/Sources/MSrc/project.pj $
% $Revision: 1.23 $
% $Date: 2011/09/15 07:33:14MESZ $
%
% Copyright ?2011 dSPACE GmbH. All rights reserved.


switch action

    case 'GetDlgInfo'
        hBlock = varargin{1};
        dlgInfo = tl_get_dlginfodefaults('tlsim');
        titleName = 'Custom Code';
        pathinfo = tl_pathinfo(hBlock);
        dlgInfo.title = sprintf('TargetLink %s: %s', titleName, pathinfo.shortDisplayName);
        dlgInfo.pageNames = {
            'Interface'...
            'Code & Logging'...
            'Documentation'};
        varargout{1} = dlgInfo;
        varargout{2} = get_tlcg_data(hBlock);

    case 'CtrlPositions'
        pageName     = varargin{1};
        commonGeom   = varargin{2};
        sheetDims    = varargin{4};
        switch pageName
            case 'Interface'
                [sheetDims, ctrlPos] = ...
                    FcnCalcInterfaceCtrlPositions(commonGeom);

            case 'Code & Logging'
                [sheetDims, ctrlPos] = ...
                    FcnCalcCodeCtrlPositions(commonGeom, sheetDims);

            case 'Documentation'
                bTblBlock = 0;
                bCodeComment = 1;
                [sheetDims, ctrlPos] = ...
                    TLManageDocCtrls('ctrlpos', commonGeom, sheetDims, ...
                    bCodeComment, bTblBlock);
        end
        varargout{1} = sheetDims;
        varargout{2} = ctrlPos;

    case 'Create'
        pageName = varargin{1};
        dlgfig   = varargin{2};
        dlgdata  = varargin{3};
        pageNum  = strmatch(pageName, dlgdata.pageNames, 'exact');
        switch pageName
            case 'Interface'
                dlgdata = FcnCreateInterfacePage(pageNum, dlgfig, dlgdata);

            case 'Code & Logging'
                dlgdata = FcnCreateCodePage(pageNum, dlgfig, dlgdata);

            case 'Documentation'
                dlgdata = TLManageDocCtrls('create', pageNum, dlgfig, dlgdata);
        end
        dlgdata.pageData{pageNum}.ctrlPos = [];
        varargout{1} = dlgdata;

    case 'Manage'
        pageName   = varargin{1};
        dlgfig     = varargin{2};
        dlgdata    = varargin{3};
        pageAction = varargin{4};
        pageNum    = strmatch(pageName, dlgdata.pageNames, 'exact');
        switch pageName
            case 'Interface'
                [dlgdata, bModified] = ...
                    FcnManageInterfacePage(pageNum, dlgfig, dlgdata, pageAction);

            case 'Code & Logging'
                [dlgdata, bModified] = ...
                    FcnManageCodePage(pageNum, dlgfig, dlgdata, pageAction);

            case 'Documentation'
                [dlgdata, bModified] = ...
                    TLManageDocCtrls('callback', pageNum, dlgfig, dlgdata, pageAction);
        end
        varargout{1} = dlgdata;
        varargout{2} = bModified ;

    case 'ManageSystemIcons',
        dlgfig     = varargin{1};
        dlgdata    = varargin{2};
        pageAction = varargin{3};
        [dlgdata, bModified] = FcnManageSystemIcons(dlgfig,dlgdata,pageAction);
        varargout{1} = dlgdata;
        varargout{2} = bModified;

    case 'Update'
        dlgfig   = varargin{1};
        dlgdata  = varargin{2};
        pageNum  = varargin{3};
        pageName = dlgdata.pageNames{pageNum};

        switch pageName
            case 'Interface'
                dlgdata = FcnUpdateInterfacePage(dlgdata, dlgfig, pageNum);

            case 'Code & Logging'
                dlgdata = FcnUpdateCodePage(dlgdata, dlgfig, pageNum);

            case 'Documentation'
                TLManageDocCtrls('update', pageNum, dlgfig, dlgdata);
        end
        varargout{1} = dlgdata;

    case 'Apply'
        dlgdata  = varargin{2};
        bClose   = varargin{3};
        [dlgdata, bClose] = tl_apply_blockdata(dlgdata, bClose);
        varargout{1} = dlgdata;
        varargout{2} = bClose;

    otherwise
        error(['Invalid action "' action '"']);

end


%-----------------------------------------------------------------------------------------
% FcnManageSystemIcons manage actions of toolbar icons
%
% INPUT ARGUMENTS
%   dlgfig      handle for dialog figure
%   dlgdata     dialog data
%   action      action at one control of current page
%
% OUTPUT ARGUMENTS
%   dlgdata     modified dialog data
%   bModified   flag = 1, if dialog data are modified, =0 otherwise
%-----------------------------------------------------------------------------------------
function [dlgdata, bModified] = FcnManageSystemIcons(dlgfig, dlgdata, action) %#ok

bModified = false;
switch action
    case 'EditCode'
        % look for associated production code file
        [codefile,blockstr] = get_codefile(dlgdata.model);
        if ~isempty(codefile)
            codeedit(codefile,blockstr);
        end

    case 'ViewCode'
        % get name of variable from popup
        idx = get(dlgdata.pageData{1}.children.selectPopup,'Value');
        varNames = get(dlgdata.pageData{1}.children.selectPopup,'String');
        varName = varNames{idx};
        blockVar = '';
        fields = fieldnames(dlgdata.data);

        % iterate struct fields
        for k=1:numel(fields)
            fieldValue = getfield(dlgdata.data,fields{k}); %#ok
            if isfield(fieldValue,'varname')
                idx = find(strcmp({fieldValue.varname},varName));
                if numel(idx) == 1
                    blockVar = fields{k};
                    break;
                end
            end
        end

        if ~strcmp(blockVar,'param')
            tl_create_links_to_model('ShowComputation',dlgdata.model, blockVar, idx);
        else
            tl_create_links_to_model('ShowDeclaration',dlgdata.model, blockVar, idx);
        end

    otherwise
        error('Invalid callback');

end % switch(action)


%-----------------------------------------------------------------------------------------
% FcnCalcInterfaceCtrlPositions calculates positions for all controls on interface page
%
% INPUT ARGUMENTS
%   commonGeom      common geometrie information
%
% OUTPUT ARGUMENTS
%   sheetDims       modified dimension of sheet
%   ctrlPos         positions of controls
%
% HINT:
% Positions are calculated from the bottom left of the figure to avoid
% dependencies on figure size
%-----------------------------------------------------------------------------------------
function [sheetDims, ctrlPos] = FcnCalcInterfaceCtrlPositions(commonGeom)

excludedCtrls = {'saturate', 'inheritproperties'};
[sheetDims, ctrlPos, col, colDelta, rowDelta] = ...
    tl_calc_ctrls_positions(commonGeom, excludedCtrls);

strings_and_styles = {
    'Select:',            'text'; ...
    'Work variables',     'text'; ...
    'Initial cond.:',     'text'; ...
    'Direct feedthrough', 'checkbox'; ...
    'Use value of Data Dictionary variable', 'checkbox'};

[selectLabelSize, ...
    workVariableLabelSize, ...
    initConditionLabelSize, ...
    multUseCheckboxSize, ...
    useDDValueCheckboxSize] = ...
    ds_get_uicontrol_sizes(commonGeom,strings_and_styles);

% use sizes from standard scaling controls
varLabelSize = ctrlPos.descLabel(3:4);
varEditSize = ctrlPos.varEdit(3:4);

% move column 4
col(4) = col(2) + varEditSize(1) + colDelta / 3;

% calculate extra space needed for select popup
dy = commonGeom.editHeight + rowDelta ...
    + commonGeom.checkboxHeight + rowDelta;

% enlarge tlcgoptGroupbox and move addoptGroupbox
ctrlPos.tlcgoptGroupbox(4) = ctrlPos.tlcgoptGroupbox(4) + dy;
ctrlPos.addoptGroupbox(2)  = ctrlPos.addoptGroupbox(2)  + dy;

% define new height for addoptGroupbox
ctrlPos.addoptGroupbox(4) = 3 * commonGeom.editHeight ...
    + 2 * rowDelta ...
    + commonGeom.frameBottomEdgeBuffer ...
    + commonGeom.frameTopEdgeBuffer;

% supplement tlcgGroupbox
cy = ctrlPos.descLabel(2) + commonGeom.editHeight + rowDelta;

% direct feedthrough and scalar checkbox
cx = col(2);
ctrlPos.multUseCheckbox = [cx cy multUseCheckboxSize];

% use ddv checkbox
cx = col(6);
ctrlPos.useDDValueCheckbox = [cx, cy, useDDValueCheckboxSize];

% select label
cx = col(1);
cy = cy + commonGeom.checkboxHeight + rowDelta;
ctrlPos.selectLabel = [cx cy selectLabelSize];

% select popup
cx = col(2);
ctrlPos.selectPopup = [cx cy ctrlPos.varEdit(3:4)];

% initial condition label
cx = col(4);
ctrlPos.initConditionLabel = [cx, cy, initConditionLabelSize];

% initial condition edit field
cx = col(6);
ctrlPos.initConditionEdit = [cx, cy, ctrlPos.varEdit(3:4)];

% 3rd row
cy = commonGeom.frameBottomEdgeBuffer;

% state label
cx = col(1);
ctrlPos.stateLabel = [cx cy varLabelSize];

% state edit field
cx = col(2);
ctrlPos.stateEdit = [cx cy varEditSize];

% 2nd row
cy = cy + commonGeom.editHeight + rowDelta;

% output label
cx = col(1);
ctrlPos.outputLabel = [cx cy varLabelSize];

% output edit field
cx = col(2);
ctrlPos.outputEdit = [cx cy varEditSize];

% work label
cx = col(4);
ctrlPos.workLabel = [cx cy workVariableLabelSize];

% work edit field
cx = col(4) + workVariableLabelSize(1) + colDelta/3;
ctrlPos.workEdit = [cx cy varEditSize];

% 1st row
cy = cy + commonGeom.editHeight + rowDelta;

% input label
cx = col(1);
ctrlPos.inputLabel = [cx cy varLabelSize];

% input edit field
cx = col(2);
ctrlPos.inputEdit = [cx cy varEditSize];

% parameters label
cx = col(4);
ctrlPos.paramLabel = [cx cy workVariableLabelSize];

% parameter edit label
cx = col(4) + workVariableLabelSize(1) + colDelta/3;
ctrlPos.paramEdit = [cx cy varEditSize];

% increase sheet dimensions
sheetDims(2) = sheetDims(2) ...
    + ctrlPos.addoptGroupbox(4) ...
    + commonGeom.textHeight ...
    + dy;


%-----------------------------------------------------------------------------------------
% FcnCreateInterfacePage creates the figure window
%
% INPUT ARGUMENTS
%   pageNum     number of current page
%   dlgfig      handle for dialog figure
%   dlgdata     dialog data
%
% OUTPUT ARGUMENTS
%   dlgdata     modified dialog data
%-----------------------------------------------------------------------------------------
function dlgdata = FcnCreateInterfacePage(pageNum, dlgfig, dlgdata)

ctrlPos = dlgdata.pageData{pageNum}.ctrlPos;
pageName = dlgdata.pageNames{pageNum};
% create the addoptGroupbox which will contain further options
Children.addoptGroupbox = uipanel( ...
    'Parent',            dlgfig, ...
    'Title',            {'Custom code symbols'}, ...
    'Units',            'pixels', ...
    'Position',          ctrlPos.addoptGroupbox);

% interface variable controls
Children.inputLabel = uicontrol( ...
    'Parent',             Children.addoptGroupbox, ...
    'Style',              'text', ...
    'String',             'Inputs:', ...
    'Position',           ctrlPos.inputLabel);

Children.inputEdit = uicontrol( ...
    'Parent',             Children.addoptGroupbox, ...
    'Style',              'edit', ...
    'Position',           ctrlPos.inputEdit, ...
    'Callback',           sprintf('tldlg(''%s'',gcbf,''inputEdit'')',pageName));

Children.outputLabel = uicontrol( ...
    'Parent',             Children.addoptGroupbox, ...
    'Style',              'text', ...
    'String',             'Outputs:', ...
    'Position',           ctrlPos.outputLabel);

Children.outputEdit = uicontrol( ...
    'Parent',             Children.addoptGroupbox, ...
    'Style',              'edit', ...
    'Position',           ctrlPos.outputEdit, ...
    'Callback',           sprintf('tldlg(''%s'',gcbf,''outputEdit'')',pageName));

Children.stateLabel = uicontrol( ...
    'Parent',             Children.addoptGroupbox, ...
    'Style',              'text', ...
    'String',             'States:', ...
    'Position',           ctrlPos.stateLabel);

Children.stateEdit = uicontrol( ...
    'Parent',             Children.addoptGroupbox, ...
    'Style',              'edit', ...
    'Position',           ctrlPos.stateEdit, ...
    'Callback',           sprintf('tldlg(''%s'',gcbf,''stateEdit'')',pageName));

Children.paramLabel = uicontrol( ...
    'Parent',             Children.addoptGroupbox, ...
    'Style',              'text', ...
    'String',             'Parameters:', ...
    'Position',           ctrlPos.paramLabel);

Children.paramEdit = uicontrol( ...
    'Parent',             Children.addoptGroupbox, ...
    'Style',              'edit', ...
    'Position',           ctrlPos.paramEdit, ...
    'Callback',           sprintf('tldlg(''%s'',gcbf,''paramEdit'')',pageName));

Children.workLabel = uicontrol( ...
    'Parent',             Children.addoptGroupbox, ...
    'Style',              'text', ...
    'String',             'Work variables:', ...
    'Position',           ctrlPos.workLabel);

Children.workEdit = uicontrol( ...
    'Parent',             Children.addoptGroupbox, ...
    'Style',              'edit', ...
    'Position',           ctrlPos.workEdit, ...
    'Callback',           sprintf('tldlg(''%s'',gcbf,''workEdit'')',pageName));

dlgdata.pageData{pageNum}.children = Children;

dlgdata = TLManageVariableCtrls('create', pageNum, dlgfig, dlgdata);
dlgdata = TLManageScalingCtrls('create', pageNum, dlgfig, dlgdata);

Children = dlgdata.pageData{pageNum}.children;

% variable select controls
Children.selectLabel = uicontrol( ...
    'Parent',             Children.tlcgoptGroupbox, ...
    'Style',              'text', ...
    'String',             'Select:', ...
    'Position',           ctrlPos.selectLabel);

Children.selectPopup = uicontrol( ...
    'Parent',             Children.tlcgoptGroupbox, ...
    'Style',              'Popupmenu', ...
    'BackgroundColor',    'w', ...
    'String',             ' ', ...
    'Position',           ctrlPos.selectPopup, ...
    'Callback',           sprintf('tldlg(''%s'',gcbf,''selectPopup'')',pageName));

% direct feedthrough and scalar checkbox
Children.multUseCheckbox = uicontrol( ...
    'Parent',             Children.tlcgoptGroupbox, ...
    'Style',              'checkbox', ...
    'Position',           ctrlPos.multUseCheckbox, ...
    'Callback',           sprintf('tldlg(''%s'',gcbf,''multUseCheckbox'')',pageName));

% initial condition controls
Children.initConditionLabel = uicontrol( ...
    'Parent',             Children.tlcgoptGroupbox, ...
    'Style',              'text', ...
    'Position',           ctrlPos.initConditionLabel);

Children.initConditionEdit = uicontrol( ...
    'Parent',             Children.tlcgoptGroupbox, ...
    'Style',              'edit', ...
    'Position',           ctrlPos.initConditionEdit, ...
    'Callback',           sprintf('tldlg(''%s'',gcbf,''initConditionEdit'')',pageName));

Children.useDDValueCheckbox = uicontrol( ...
    'Parent',             Children.tlcgoptGroupbox, ...
    'Style',              'checkbox', ...
    'Position',           ctrlPos.useDDValueCheckbox, ...
    'Callback',           sprintf('tldlg(''%s'',gcbf,''useDDValueCheckbox'')',pageName));

dlgdata.pageData{pageNum}.children = Children;

allGroupboxChildren = get(dlgdata.pageData{pageNum}.children.tlcgoptGroupbox, 'Children');
% reorder controls: put additional controls infront of general controls
uistack(allGroupboxChildren(1:6), 'bottom');
% reset panel title for correct display
title = get(dlgdata.pageData{pageNum}.children.tlcgoptGroupbox, 'Title');
set(dlgdata.pageData{pageNum}.children.tlcgoptGroupbox, 'Title', title{1});


%-----------------------------------------------------------------------------------------
% FcnManageInterfacePage manages control actions of interface page
%
% INPUT ARGUMENTS
%   pageNum     number of current page
%   dlgfig      handle for dialog figure
%   dlgdata     dialog data
%   pageAction  action at one control of current page
%
% OUTPUT ARGUMENTS
%   dlgdata     modified dialog data
%   bModified   flag = 1, if dialog data are modified, =0 otherwise
%-----------------------------------------------------------------------------------------
function [dlgdata, bModified] = FcnManageInterfacePage(pageNum, dlgfig, dlgdata, pageAction)

Children = dlgdata.pageData{pageNum}.children;
data = dlgdata.data;
varnames = get(Children.selectPopup, 'String');
selectIdx = get(Children.selectPopup, 'Value');
[datafield, fieldname, idx] = FcnGetDatafield(data, varnames, selectIdx);

switch pageAction
    case {'inputEdit', 'outputEdit', 'stateEdit', 'paramEdit', 'workEdit'}
        field = pageAction(1:end-4);
        varstr = get(Children.(pageAction), 'String');
        dlgdata = FcnHandleVarEdit(dlgdata, field, varstr);
        bModified = true;
        
    case 'selectPopup'
        dlgdata.signalName = varnames{get(Children.selectPopup, 'Value')};
        bModified = true;
        
    case 'initConditionEdit'
        initConditionStr = deblank(get(Children.initConditionEdit,'String'));
        if ~isempty(initConditionStr) && isempty(findstr(initConditionStr,'|'))
            bIsValid = true;
            if strcmp(initConditionStr, 'ddv')
                if isempty(datafield.variable)
                    bIsValid = false;
                    beep;
                else
                    initConditionStr = ['ddv(''', datafield.variable, ''')'];
                    datafield.useddvariablevalue = true;
                end
            end
            if bIsValid
                if isfield(datafield, 'value')
                    datafield.value = initConditionStr;
                else
                    datafield.initial = initConditionStr;
                end
            end
            dlgdata.data.(fieldname)(idx) = datafield;
        else
            beep;
        end
        bModified = true;
        
    case 'multUseCheckbox'
        if isfield(datafield, 'scalar')
            datafield.scalar = get(Children.multUseCheckbox,'Value');
        else
            datafield.feedthrough = get(Children.multUseCheckbox,'Value');
        end
        dlgdata.data.(fieldname)(idx) = datafield;
        bModified = true;
        
    case 'useDDValueCheckbox'
        if get(Children.useDDValueCheckbox, 'Value')
            value = ['ddv(''', datafield.variable, ''')'];
            if isfield(datafield, 'value')
                datafield.value = value;
            else
                datafield.initial = value;
            end
            datafield.useddvariablevalue = true;
        else
            datafield.useddvariablevalue = false;
        end
        dlgdata.data.(fieldname)(idx) = datafield;
        bModified = true;
        
    otherwise
        [dlgdata, bModified1] = ...
            TLManageVariableCtrls('manage',pageNum,dlgfig,dlgdata,pageAction,fieldname);
        [dlgdata, bModified2] = ...
            TLManageScalingCtrls('manage',pageNum,dlgfig,dlgdata,pageAction,fieldname);
        bModified = bModified1 || bModified2;
end


%--------------------------------------------------------------------------
% FcnUpdateInterfacePage updates the controls of the interface tab
%
% INPUT ARGUMENTS
%   dlgdata     dialog data
%   dlgfig      figure handle of dialog
%   pageNum     page Number
%
% OUTPUT ARGUMENTS
%   dlgdata     modified dialog data
%--------------------------------------------------------------------------
function dlgdata = FcnUpdateInterfacePage(dlgdata, dlgfig, pageNum)

Children = dlgdata.pageData{pageNum}.children;
varNames = FcnGetVarNames(dlgdata.data,'');

inputEditCtrlStatus = struct('enable', 'on', 'string', '');
outputEditCtrlStatus = struct('enable', 'on', 'string', '');
stateEditCtrlStatus = struct('enable', 'on', 'string', '');
paramEditCtrlStatus = struct('enable', 'on', 'string', '');
workEditCtrlStatus = struct('enable', 'on', 'string', '');
selectPopupCtrlStatus = struct('enable', 'on');
initConditionEditCtrlStatus = struct('enable', 'off', 'string', '');
initConditionLabelCtrlStatus = struct('enable', 'on', 'string', '');
multUseCheckboxCtrlStatus = struct('enable', 'off', 'value', 0, 'string', '');
useDDValueCheckboxCtrlStatus = struct('enable', 'off', 'value', 0, 'string', '');

% cover the case that no variables are specified
if isempty(varNames)
    % deactivate all production code options
    allChildren = dlgdata.pageData{pageNum}.children;
    ctrlNames = fieldnames(allChildren);
    widthGroupCtrls = { ...
        'addoptGroupbox'; ...
        'workLabel'; ...
        'workEdit'; ...
        'paramLabel'; ...
        'paramEdit'; ...
        'stateLabel'; ...
        'stateEdit'; ...
        'outputLabel'; ...
        'outputEdit'; ...
        'inputLabel'; ...
        'inputEdit'};
    ctrlNames = setdiff(ctrlNames, widthGroupCtrls);
    userData.ctrlStatus.enable = 'off';
    structfun(@(c) (set(c,'UserData',userData)), allChildren);
    TLSetCtrlsStatus(dlgfig, allChildren, ctrlNames);

    varEditCtrlsList = widthGroupCtrls(~cellfun('isempty', regexp(widthGroupCtrls, 'Edit', 'match')));
    for ctrlsNo = 1:length(varEditCtrlsList)
        ctrl = Children.(varEditCtrlsList{ctrlsNo});
        UserData = get(ctrl, 'UserData');
        UserData.ctrlStatus = eval([varEditCtrlsList{ctrlsNo} 'CtrlStatus']);
        set(ctrl, 'UserData', UserData);
    end

    TLSetCtrlsStatus(dlgfig, Children, varEditCtrlsList);
    return
end

% determine the selected variable
selectPopupCtrlStatus.string = varNames;
if isfield(dlgdata, 'signalName') && ~isempty(find(strcmp(varNames,dlgdata.signalName) == 1, 1))
    % current signal is found in varname list
    fieldIdx = find(strcmp(varNames,dlgdata.signalName) == 1, 1);
else
    fieldIdx = min([get(Children.selectPopup, 'Value'), length(varNames)]);
end
selectPopupCtrlStatus.value = fieldIdx;
dlgdata.signalName = varNames{fieldIdx};

% extract the datafield from blockdata
[datafield, fieldname, index, valuename] = FcnGetDatafield(dlgdata.data, varNames, fieldIdx);
dlgdata.currentSignal = index;

% invoke standard update methods
dlgdata = TLManageVariableCtrls('update', pageNum, dlgdata, fieldname);
constraint = [];
if ~isempty(valuename)
    [value, constraint, bCompliant] = tl_get_param_constraints(datafield, ...
        dlgdata.extdata.(fieldname)(index), valuename);
end
dlgdata = TLManageScalingCtrls('update', pageNum, dlgdata, fieldname, constraint);

calculatedLabelCtrlStatus = tl_get_control_userdata(Children.calculatedLabel);
upperCalculatedValueCtrlStatus = tl_get_control_userdata(Children.upperCalculatedValue);
lowerCalculatedValueCtrlStatus = tl_get_control_userdata(Children.lowerCalculatedValue);
simulatedLabelCtrlStatus = tl_get_control_userdata(Children.simulatedLabel);
upperSimulatedValueCtrlStatus = tl_get_control_userdata(Children.upperSimulatedValue);
lowerSimulatedValueCtrlStatus = tl_get_control_userdata(Children.lowerSimulatedValue);

% for parameters there are no simulated ranges. Instead, write min/max of value
if ~isempty(valuename)
    if ~bCompliant
        initConditionEditCtrlStatus.iserror = 1;
    end
    if strcmp(fieldname, 'param')
        % standard parameter is handled in TLManageScalingCtrls
        simulatedLabelCtrlStatus.string = 'of parameter';
    else
        % state must have special handling
        simulatedLabelCtrlStatus.string = 'of initial cond.';
        % check and set state constraints
        if ~isempty(constraint)
            lowerSimulatedValueCtrlStatus.string = sprintf('%0.6g', min(constraint));
            upperSimulatedValueCtrlStatus.string = sprintf('%0.6g', max(constraint));
        else
            upperSimulatedValueCtrlStatus.string = 'n.a.';
            uppSimLimitCtrlStatus.string = 'n.a.';
        end
    end
else
    simulatedLabelCtrlStatus.string = 'Simulated';
    if any(strcmp(fieldname, {'input', 'work'}))
        simulatedLabelCtrlStatus.enable = 'off';
        upperSimulatedValueCtrlStatus.enable = 'off';
        lowerSimulatedValueCtrlStatus.enable = 'off';
    end
end
calculatedLabelCtrlStatus.enable = 'off';
upperCalculatedValueCtrlStatus.enable = 'off';
lowerCalculatedValueCtrlStatus.enable = 'off';

data = dlgdata.data;
inputEditCtrlStatus.string = FcnDatafield2Str(data, 'input');
outputEditCtrlStatus.string = FcnDatafield2Str(data, 'output');
stateEditCtrlStatus.string = FcnDatafield2Str(data, 'state');
paramEditCtrlStatus.string = FcnDatafield2Str(data, 'param');
workEditCtrlStatus.string = FcnDatafield2Str(data, 'work');

switch fieldname
    case 'param'
        multUseCheckboxCtrlStatus.value = datafield.scalar;
        multUseCheckboxCtrlStatus.enable = flag2str(dlgdata.bIsFullVs);
        multUseCheckboxCtrlStatus.string = 'Scalar';
        multUseCheckboxCtrlStatus.tooltip = 'Current parameter is a scalar';
        if datafield.useddvariablevalue
            initConditionEditCtrlStatus.enable = 'inactive';
        else
            initConditionEditCtrlStatus.enable = 'on';
        end
        initConditionEditCtrlStatus.string = datafield.value;
        initConditionEditCtrlStatus.tooltip = 'Enter a MATLAB expression which returns the parameter value';
        initConditionLabelCtrlStatus.string = 'Value:';
        useDDValueCheckboxCtrlStatus.enable = flag2str(~isempty(datafield.variable));
        useDDValueCheckboxCtrlStatus.value = datafield.useddvariablevalue;
        useDDValueCheckboxCtrlStatus.string = 'Use value of Data Dictionary variable';
    case 'state'
        if datafield.useddvariablevalue
            initConditionEditCtrlStatus.enable = 'inactive';
        else
            initConditionEditCtrlStatus.enable = 'on';
        end
        initConditionEditCtrlStatus.string = datafield.initial;
        initConditionEditCtrlStatus.tooltip = 'Enter a MATLAB expression which returns the initial condition of the current state';
        initConditionLabelCtrlStatus.string = 'Initial cond.:';
        useDDValueCheckboxCtrlStatus.enable = flag2str(~isempty(datafield.variable));
        useDDValueCheckboxCtrlStatus.value = datafield.useddvariablevalue;
        useDDValueCheckboxCtrlStatus.string = 'Use value of Data Dictionary variable';
    case 'input'
        multUseCheckboxCtrlStatus.value = datafield.feedthrough;
        multUseCheckboxCtrlStatus.enable = flag2str(dlgdata.bIsFullVs);
        multUseCheckboxCtrlStatus.string = 'Direct feedthrough';
        multUseCheckboxCtrlStatus.tooltip = 'Current input is directly fed through the output';
    case {'output', 'work'}
        % just simextrema
end

widthEditCtrlStatus = tl_get_control_userdata(Children.widthEdit);
widthUpButtonCtrlStatus = tl_get_control_userdata(Children.widthUpButton);
widthDownButtonCtrlStatus = tl_get_control_userdata(Children.widthDownButton);
if strcmp(fieldname, 'param')
    widthEditCtrlStatus.enable = 'off';
    widthEditCtrlStatus.string = '';
else
    widthEditCtrlStatus.enable = 'inactive';
    widthEditCtrlStatus.string = abs(dlgdata.data.(fieldname)(index).width);
end
widthUpButtonCtrlStatus.enable = 'off';
widthDownButtonCtrlStatus.enable = 'off';

extraCtrlsList = {
    'inputEdit', ...
    'outputEdit', ...
    'stateEdit', ...
    'paramEdit', ...
    'workEdit', ...
    'selectPopup', ...
    'initConditionEdit', ...
    'initConditionLabel', ...
    'multUseCheckbox', ...
    'useDDValueCheckbox'};
standardCtrlsList = {
    'widthEdit', ...
    'widthUpButton', ...
    'widthDownButton', ...
    'calculatedLabel', ...
    'upperCalculatedValue', ...
    'lowerCalculatedValue', ...
    'simulatedLabel', ...
    'upperSimulatedValue', ...
    'lowerSimulatedValue'};
ctrlsList = [extraCtrlsList standardCtrlsList];
for ctrlsNo = 1:length(ctrlsList)
    ctrl = Children.(ctrlsList{ctrlsNo});
    UserData = get(ctrl, 'UserData');
    UserData.ctrlStatus = eval([ctrlsList{ctrlsNo} 'CtrlStatus']);
    set(ctrl, 'UserData', UserData);
end

dlgdata.data.(fieldname)(index)= datafield;
TLManageVariableCtrls('setCtrls', pageNum, dlgfig, dlgdata);
TLManageScalingCtrls('setCtrls', pageNum, dlgfig, dlgdata);
TLSetCtrlsStatus(dlgfig, Children, extraCtrlsList);


%--------------------------------------------------------------------------
% FcnGetVarNames gets string with all variable names
%
% INPUT ARGUMENTS
%   data        current block data
%   field       current field
%
% OUTPUT ARGUMENTS
%   varNames    varable names of current field
%--------------------------------------------------------------------------
function varNames = FcnGetVarNames(data, field)

varNames = {};
if ~strcmp(field,'input')  && isfield(data,'input')
    varNames = {varNames{:} data.input.varname};
end
if ~strcmp(field,'output') && isfield(data,'output')
    varNames = {varNames{:} data.output.varname};
end
if ~strcmp(field,'state')  && isfield(data,'state')
    varNames = {varNames{:} data.state.varname};
end
if ~strcmp(field,'param')  && isfield(data,'param')
    varNames = {varNames{:} data.param.varname};
end
if ~strcmp(field,'work')   && isfield(data,'work')
    varNames = {varNames{:} data.work.varname};
end


%--------------------------------------------------------------------------
% FcnDatafield2Str evaluates strings for variable edit fields
%
% INPUT ARGUMENTS
%   data        current block data
%   field       current field
%
% OUTPUT ARGUMENTS
%   str         varable names
%--------------------------------------------------------------------------
function str = FcnDatafield2Str(data, field)

str = '';
if ~isfield(data,field)
    return
end;
datafield = data.(field);
for i = 1:length(datafield)
    if datafield(i).width > 1 && ~strcmp(field, 'param')
        str = [str datafield(i).varname '[' num2str(datafield(i).width) '], ']; %#ok<AGROW>
    else
        str = [str datafield(i).varname ', ']; %#ok<AGROW>
    end
end
str = str(1:end-2);


%--------------------------------------------------------------------------
% FcnGetDatafield gets current datafield
%
% INPUT ARGUMENTS
%   data        current block data
%   varNames    current variable names
%   selectIndex current index
%
% OUTPUT ARGUMENTS
%   datafield   current datafield
%   fieldname   current fieldname
%   idx         current index
%   valuename   current valuename
%--------------------------------------------------------------------------
function [datafield, fieldname, idx, valuename] = FcnGetDatafield(data, varNames, selectIndex)

valuename = '';
if iscell(varNames)
    varname = varNames{selectIndex};
else
    if isequal(varNames, ' ')
        datafield = '';
        fieldname = '';
        idx = [];
        return;
    else
        varname = varNames;
    end
end

if isfield(data,'input')
    idx = find(strcmp({data.input.varname},varname) == 1);
    if ~isempty(idx)
        datafield = data.input(idx);
        fieldname = 'input';
        return;
    end
end

if isfield(data,'output')
    idx = find(strcmp({data.output.varname},varname) == 1);
    if ~isempty(idx)
        datafield = data.output(idx);
        fieldname = 'output';
        return;
    end
end

if isfield(data,'state')
    idx = find(strcmp({data.state.varname},varname) == 1);
    if ~isempty(idx)
        datafield = data.state(idx);
        fieldname = 'state';
        valuename = 'initial';
        return;
    end
end

if isfield(data,'param')
    idx = find(strcmp({data.param.varname},varname) == 1);
    if ~isempty(idx)
        datafield = data.param(idx);
        fieldname = 'param';
        valuename = 'value';
        return;
    end
end

if isfield(data,'work')
    idx = find(strcmp({data.work.varname},varname) == 1);
    if ~isempty(idx)
        datafield = data.work(idx);
        fieldname = 'work';
    end
end


%--------------------------------------------------------------------------
% FcnHandleVarEdit handles variable edit fields
%
% INPUT ARGUMENTS
%   dlgdata     dialog data
%   field       current field
%   varstr      current variable
%
% OUTPUT ARGUMENTS
%   dlgdata     modified dialog data
%--------------------------------------------------------------------------
function dlgdata = FcnHandleVarEdit(dlgdata, field, varstr)

data = dlgdata.data;
othervars = FcnGetVarNames(data,field);

% get user input, remove blanks
varstr = strrep(varstr, ' ', '');

% push variable names into cell array of strings
if ~isempty(varstr)
    vars = eval(['{''' strrep(varstr,',',''',''') '''}'], '[]');
else
    vars = {};
end
if ~iscell(vars)              % check for syntax errors
    beep;
else
    if size(vars,1) > 1        % check if names were given as row vector (or empty)
        beep;
    else
        nvars = length(vars);
        widths = cell(1,nvars);
        i = 1;
        ok = 1;
        while i <= nvars && ok == 1
            [widths{i}, vars{i}, ok] = FcnGetVarWidth(vars{i});
            if ok == 0
                ds_msgbox('Message', ...
                    ['''' vars{i} ''' is not a valid variable specification!'], ...
                    'Title','Variable name syntax error','Style','Error');
            end
            if strcmp(field,'param') && widths{i} > 1 % 'param' field
                ds_msgbox('Message', ...
                    {['''' vars{i} ''' is a vector'], ...
                    'which is not possible for parameters.'}, ...
                    'Title','No vectors for parameters','Style','Error');
                ok = 0;
            end
            i = i+1;
        end

        i = 1;
        while i<=nvars && ok == 1
            ok = ds_regexp('[_a-zA-Z]+[_a-zA-Z0-9]*', vars{i});
            if ok == 0
                ds_msgbox('Message',['''' vars{i} ''' is not a valid C identifier!'], ...
                    'Title','Check input','Style','Error');
                % ...  and inambiguous
            elseif sum(strcmp({othervars{:} vars{:}},vars{i})) > 1
                ds_msgbox('Message',['''' vars{i} ''' is not unique!'], ...
                    'Title','Variable name ambiguity','Style','Error');
                ok = 0;
                % ... and not identical to a current usertype ...
            elseif ~isempty(dsdd('Find','//DD0/Pool/Typedefs','name',vars{i}))
                ds_msgbox('Message', ...
                    ['There is already a user-defined datatype ''' vars{i} '''!'], ...
                    'Title','Conflict with name of usertype','Style','Error');
                ok = 0;

                % ... nor to a variable class ...
            elseif ~isempty(dsdd('Find','//DD0/Pool/VariableClasses','name',vars{i}))
                ds_msgbox('Message', ...
                    ['There is already a variable class ''' vars{i} '''!'], ...
                    'Title','Conflict with name of variable class','Style','Error');
                ok = 0;
            end
            i = i+1;
        end
    end   % if size(vars,1) > 1

    if ok == 0
        beep;
    else                     % everything seems alright
        if nvars == 0
            if isfield(data,field)
                data = rmfield(data,field);
                if strcmp(field,'output') && isfield(data,'logdata')
                    data = rmfield(data,'logdata');
                end
            end
        else
            % get default field content
            d = tl_manage_blockset('GetDataDescription', 'TL_CustomCode');
            idx = find(strcmp({d{:,1}},field));
            df = d{idx,2};
            for i=1:size(df,1)
                eval(['defaultfield.' df{i,1} ' = df{i,2}{1,1};']);
            end
            idx = find(strcmp({d{:,1}},'logdata'));
            dl = d{idx,2};
            for i=1:size(dl,1)
                eval(['deflogdata.' dl{i,1} ' = dl{i,2}{1,1};']);
            end

            % check if field exists
            if ~isfield(data,field)
                eval(['data.' field ' = defaultfield;']);
                if strcmp(field,'output') %& ~isfield(data,'logdata')
                    data.logdata = deflogdata;
                end
            end
            idx = zeros(size(vars));
            oldVarNames = eval(['{data.' field '.varname}']);
            for n=1:length(vars)
                z = find(strcmp(oldVarNames,vars{n}));
                if ~isempty(z)
                    idx(n) = z;
                end
            end

            % expand or shrink field
            len = length(eval(['data.' field]));
            if len < nvars
                for i=1:length(df)
                    eval(['[data.' field '(len+1:nvars).' df{i,1} '] = deal(defaultfield.' df{i} ');']);
                end
                if strcmp(field,'output')
                    [data.logdata(len+1:nvars)] = deal(data.logdata(end));
                end
            end
            z = find(idx == 0);
            idx(z) = z;
            data.(field) = data.(field)(idx);
            %         eval(['data.' field ' = data.' field '(idx);'])
            if strcmp(field,'output')
                data.logdata = data.logdata(idx);
            end

            % map names and widths
            [data.(field).varname] = deal(vars{:});
            [data.(field).width] = deal(widths{:});
            %          eval(['[data.' field '.varname]  = deal(vars{:});']);
            %          eval(['[data.' field '.width] = deal(widths{:});']);

            % name macros
            if len < nvars
                for i=len+1:nvars
                    data.(field)(i).name = [data.(field)(i).name(1:end-1) data.(field)(i).varname];
                    %               eval(['data.' field '(i).name = [data.' field '(i).name(1:end-1) data.' field '(i).varname];']);
                end
            end

            % set sizes of vectorized fields
            for i=1:nvars
                data.(field)(i).lsb = adapt_vec(data.(field)(i).lsb, widths{i}, 1);
                data.(field)(i).arb = adapt_vec(data.(field)(i).arb, widths{i}, 0);
                data.(field)(i).offset = adapt_vec(data.(field)(i).offset, widths{i}, 0);
                data.(field)(i).max = adapt_vec(data.(field)(i).max, widths{i}, NaN);
                data.(field)(i).min = adapt_vec(data.(field)(i).min, widths{i}, NaN);
            end
        end
        dlgdata.data = data;
    end    % if ok == 0
end

%-----------------------------------------------------------------------------------------
% FcnGetVarWidth separates variable name and width
%
% INPUT ARGUMENTS
%   var         current variable string
%
% OUTPUT ARGUMENTS
%   k           width
%   varname     variable name
%   ok          flag = 1, if no error, =0 otherwise
%   sc          flag = 1, if scalar, =0 otherwise
%-----------------------------------------------------------------------------------------
function [k, varname, ok, sc] = FcnGetVarWidth(var)

k = 1;
ok = 0;
varname = var;
sc = 1;

obracket = findstr(var, '[');
cbracket = findstr(var, ']');

if ~isempty(obracket) && ~isempty(cbracket)
    if numel(obracket) == 1 && numel(cbracket) == 1
        if cbracket - obracket > 1 && cbracket == length(var) && obracket > 1
            % using eval() would be faster but does not ensure that only
            % characters 0..9 are used
            k = sscanf(var(obracket+1:cbracket-1), '%f');
            if ~isempty(k)
                if k == round(k) && k >= 1
                    varname = var(1:obracket-1);
                    sc = 0; % not a scalar
                    ok = 1;
                end
            end
        end
    end
else
    ok = 1;
    sc = 1;
end


%-----------------------------------------------------------------------------------------
% FcnCalcCodeCtrlPositions calculates positions for all controls on code page
%
% INPUT ARGUMENTS
%   commonGeom      common geometrie information
%
% OUTPUT ARGUMENTS
%   sheetDims       modified dimension of sheet
%   ctrlPos         positions of controls
%
% HINT:
% Positions are calculated from the bottom left of the figure to avoid
% dependencies on figure size
%-----------------------------------------------------------------------------------------
function [sheetDims,ctrlPos] = FcnCalcCodeCtrlPositions(commonGeom, sheetDims)

excludedCtrls = {'autoscaling'};
[sheetDims, ctrlPos] = ...
    TLManageLoggingCtrls('calcCtrls', commonGeom, sheetDims, excludedCtrls);

strings_and_styles = {...
    'Use production code for floating-point simulation','checkbox';...
    'File name:',               'text';...
    repmat('m',1,24),          'edit';...
    'Sample time:',            'text';...
    ' Compile S-function ',    'pushbutton';...
    'Output to log:',          'text';...
    ' Browse ... ',            'pushbutton'};

[flpCheckboxSize, ...
    ucodefileLabelSize, ...
    ucodefileEditSize, ...
    stepsizeLabelSize, ...
    ccButtonSize, ...
    outputToLogLabelSize, ...
    browseButtonSize] = ...
    ds_get_uicontrol_sizes(commonGeom,strings_and_styles);

widths = outputToLogLabelSize(1);
[col,colWidth,colDelta,rowDelta] = ds_get_gui_columns(widths,commonGeom);

col(1) = ctrlPos.logLabel(1);
col(2) = ctrlPos.logPopup(1);

% enlarge logplotGroupbox
ctrlPos.logplotGroupbox(4) = ctrlPos.logplotGroupbox(4) ...
    + commonGeom.editHeight ...
    + rowDelta;

cy = ctrlPos.logLabel(2) + commonGeom.editHeight + rowDelta;

% output to log label
cx = col(1);
ctrlPos.outputToLogLabel = [cx cy outputToLogLabelSize];

% output to log popup
cx = col(2);
ctrlPos.outputToLogPopup = [cx cy ctrlPos.plotEdit(3:4)];

%---------------------------------------
% code options Groupbox
%---------------------------------------
% calculate dimension of optGroupbox
optGroupboxWidth = ctrlPos.logplotGroupbox(3);
optGroupboxHeight = 4 * commonGeom.editHeight ...
    + 3 * rowDelta ...
    + commonGeom.frameTopEdgeBuffer ...
    + commonGeom.frameBottomEdgeBuffer;
cy = ctrlPos.logplotGroupbox(2) ...
    + ctrlPos.logplotGroupbox(4) ...
    + commonGeom.textHeight;
cx = ctrlPos.logplotGroupbox(1);
ctrlPos.optGroupbox = [cx cy optGroupboxWidth  optGroupboxHeight];

col(3) = ctrlPos.optGroupbox(3) ...
    - ccButtonSize(1) ...
    - commonGeom.frameSideEdgeBuffer;

%---------------------------------------
% 4th row
cy = commonGeom.frameBottomEdgeBuffer;

% floating point checkbox
cx = col(1);
ctrlPos.flpCheckbox = [cx cy flpCheckboxSize];

% edit s-function button
cx = col(3);
ctrlPos.sfcnButton = [cx cy ccButtonSize];

%---------------------------------------
% 3rd row
cy = cy + commonGeom.editHeight + rowDelta;

% compile s-function button
cx = col(3);
ctrlPos.compileucodeddlButton = [cx cy ccButtonSize];

%---------------------------------------
% 2nd row
cy = cy + commonGeom.editHeight + rowDelta;

% filename label
cx = col(1);
ctrlPos.ucodefileLabel = [cx cy ucodefileLabelSize];

% filename edit field
cx = col(2);
ctrlPos.ucodefileEdit = [cx cy ucodefileEditSize];

% browse button
cx = cx + ucodefileEditSize(1) + colDelta / 3;
ctrlPos.browseButton = [cx cy  browseButtonSize];

% build s-function button
cx = col(3);
ctrlPos.builducodedllButton = [cx cy ccButtonSize];

%---------------------------------------
% 1st row
cy = cy + commonGeom.editHeight + rowDelta;

% sample time label
cx = col(1);
ctrlPos.stepsizeLabel = [cx cy stepsizeLabelSize];

% sample time edit field
cx = col(2);
ctrlPos.stepsizeEdit = [cx cy ucodefileEditSize];

% edit custom code button
cx = col(3);
ctrlPos.opencodefileButton = [cx cy ccButtonSize];

% Calculate extents (sheet dimensions).
sheetDims(2) = ctrlPos.logplotGroupbox(2) ...
    + ctrlPos.logplotGroupbox(4) ...
    + commonGeom.textHeight;


%-----------------------------------------------------------------------------------------
% FcnCreateCodePage creates the figure window
%
% INPUT ARGUMENTS
%   pageNum     number of current page
%   dlgfig      handle for dialog figure
%   dlgdata     dialog data
%
% OUTPUT ARGUMENTS
%   dlgdata     modified dialog data
%-----------------------------------------------------------------------------------------
function dlgdata = FcnCreateCodePage(pageNum, dlgfig, dlgdata)

% create logging controls
data = dlgdata.data;
dlgdata = TLManageLoggingCtrls('create', pageNum, dlgfig, dlgdata);

Children = dlgdata.pageData{pageNum}.children;
ctrlPos = dlgdata.pageData{pageNum}.ctrlPos;
pageName = dlgdata.pageNames{pageNum};

% outputToLog popup
Children.outputToLogLabel = uicontrol( ...
    'Parent',             Children.logplotGroupbox, ...
    'Style',              'text', ...
    'String',             'Output to log:', ...
    'Position',           ctrlPos.outputToLogLabel);

Children.outputToLogPopup = uicontrol( ...
    'Parent',             Children.logplotGroupbox, ...
    'Style',              'Popupmenu', ...
    'BackgroundColor',    'w', ...
    'String',             {'y'}, ...
    'Value',              1, ...
    'Position',           ctrlPos.outputToLogPopup, ...
    'Callback',           sprintf('tldlg(''%s'',gcbf,''outputToLogPopup'')',pageName));

% code options Groupbox
Children.optGroupbox = uipanel( ...
    'Parent',            dlgfig, ...
    'Title',            {'Custom code'}, ...
    'Units',            'pixels', ...
    'Position',          ctrlPos.optGroupbox);

% code edit controls
Children.builducodedllButton = uicontrol( ...
    'Parent',             Children.optGroupbox, ...
    'Style',              'pushbutton', ...
    'String',             'Build S-function', ...
    'Position',           ctrlPos.builducodedllButton, ...
    'Callback',           sprintf('tldlg(''%s'',gcbf,''builducodedllButton'')',pageName));

Children.compileucodeddlButton = uicontrol( ...
    'Parent',             Children.optGroupbox, ...
    'Style',              'pushbutton', ...
    'String',             'Compile S-function', ...
    'Position',           ctrlPos.compileucodeddlButton, ...
    'Callback',           sprintf('tldlg(''%s'',gcbf,''compileucodeddlButton'')',pageName));

Children.sfcnButton = uicontrol( ...
    'Parent',             Children.optGroupbox, ...
    'Style',              'pushbutton', ...
    'String',             'Edit S-function', ...
    'Position',           ctrlPos.sfcnButton, ...
    'Callback',           sprintf('tldlg(''%s'',gcbf,''sfcnButton'')',pageName));

Children.opencodefileButton = uicontrol( ...
    'Parent',             Children.optGroupbox, ...
    'Style',              'pushbutton', ...
    'String',             'Edit Custom Code', ...
    'Position',           ctrlPos.opencodefileButton, ...
    'Callback',           sprintf('tldlg(''%s'',gcbf,''opencodefileButton'')',pageName));

% code option controls
Children.ucodefileLabel = uicontrol( ...
    'Parent',             Children.optGroupbox, ...
    'Style',              'text', ...
    'String',             'File name:', ...
    'Position',           ctrlPos.ucodefileLabel);

Children.ucodefileEdit = uicontrol( ...
    'Parent',             Children.optGroupbox, ...
    'BackgroundColor',    'w', ...
    'String',             data.codefile, ...
    'Style',              'edit', ...
    'Position',           ctrlPos.ucodefileEdit, ...
    'Callback',           sprintf('tldlg(''%s'',gcbf,''ucodefileEdit'')',pageName));

Children.browseButton = uicontrol( ...
    'Parent',             Children.optGroupbox, ...
    'Style',              'pushbutton', ...
    'String',             'Browse ...', ...
    'Position',           ctrlPos.browseButton, ...
    'Callback',           sprintf('tldlg(''%s'',gcbf,''browseButton'')',pageName));

Children.flpCheckbox = uicontrol( ...
    'Parent',             Children.optGroupbox, ...
    'Style',              'checkbox', ...
    'Value',              data.prodcode, ...
    'String',             'Use production code for floating-point simulation', ...
    'Position',           ctrlPos.flpCheckbox, ...
    'Callback',           sprintf('tldlg(''%s'',gcbf,''flpCheckbox'')',pageName));

Children.stepsizeEdit = uicontrol( ...
    'Parent',             Children.optGroupbox, ...
    'BackgroundColor',    'w', ...
    'String',             data.dt, ...
    'Style',              'edit', ...
    'Position',           ctrlPos.stepsizeEdit, ...
    'Callback',           sprintf('tldlg(''%s'',gcbf,''stepsizeEdit'')',pageName));

Children.stepsizeLabel = uicontrol( ...
    'Parent',             Children.optGroupbox, ...
    'Style',              'text', ...
    'String',             'Sample time:', ...
    'Position',           ctrlPos.stepsizeLabel);

dlgdata.pageData{pageNum}.children = Children;


%-----------------------------------------------------------------------------------------
% FcnManageCodePage manages control actions of code page
%
% INPUT ARGUMENTS
%   pageNum     number of current page
%   dlgfig      handle for dialog figure
%   dlgdata     dialog data
%   pageAction  action at one control of current page
%
% OUTPUT ARGUMENTS
%   dlgdata     modified dialog data
%   bModified   flag = 1, if dialog data are modified, =0 otherwise
%-----------------------------------------------------------------------------------------
function [dlgdata, bModified] = FcnManageCodePage(pageNum, dlgfig, dlgdata, pageAction)

bModified = 0;
Children = dlgdata.pageData{pageNum}.children;

switch pageAction

    case 'builducodedllButton'
        hdlgfig = get(dlgfig,'Parent');
        set(hdlgfig, 'Pointer', 'watch');
        set(dlgdata.SystemButtons.StatusLabel, 'String', 'Building and compiling custom code S-function ...');
        [bSuccess, sFcnName] = tl_build_customcode_sfcn( ...
            'block', dlgdata.model, ...
            'blockData', dlgdata.data, ...
            'CompileOnly', 'no');
        if bSuccess
            set(dlgdata.SystemButtons.StatusLabel, 'String', ...
                ['Custom code S-function ' sFcnName ' successfully built.']);
        else
            set(dlgdata.SystemButtons.StatusLabel, 'String', ...
                ['Custom code S-function ' sFcnName ' could not be built.']);
        end
        hdlgfig = get(dlgfig,'Parent');
        set(hdlgfig, 'Pointer', 'arrow');

    case 'compileucodeddlButton'
        hdlgfig = get(dlgfig,'Parent');
        set(hdlgfig, 'Pointer', 'watch');
        set(dlgdata.SystemButtons.StatusLabel, 'String', 'Compiling custom code S-function ...');
        [bSuccess,sFcnName] = tl_build_customcode_sfcn( ...
            'block', dlgdata.model, ...
            'blockData', dlgdata.data, ...
            'CompileOnly', 'yes');
        if bSuccess
            set(dlgdata.SystemButtons.StatusLabel,'String', ...
                ['Custom code S-function ' sFcnName ' successfully compiled.']);
        else
            set(dlgdata.SystemButtons.StatusLabel,'String', ...
                ['Custom code S-function ' sFcnName ' could not be compiled.']);
        end
        hdlgfig = get(dlgfig,'Parent');
        set(hdlgfig, 'Pointer', 'arrow');

    case 'opencodefileButton'
        codefile = dlgdata.data.codefile;
        fpath = which(codefile);
        if isempty(fpath)
            if strcmp(ds_msgbox( ...
                    'Message', ['File ''' codefile ''' not found! Create this file?'], ...
                    'Style', 'Question', ...
                    'Title', 'Create file from template?', ...
                    'Button', {'Yes', 'No'}, ...
                    'Default', 'Yes'), 'Yes')
                dos(['copy "' fullfile(tl_get_specialfolder('CustomCode_Matlab'), 'customcode_tmpl.c') '" "' codefile '"']);
            end
            fpath = which(codefile);
        end
        if ~isempty(fpath),
            codeedit(fpath);
        end

    case 'sfcnButton'
        sFcnName = strtok(dlgdata.data.codefile,'.');
        if length(sFcnName) > 59
            sfcn_source = [sFcnName(1:59) '_flp.c'];
        else
            sfcn_source = [sFcnName '_flp.c'];
        end

        if ~isempty(which(sfcn_source))
            codeedit(which(sfcn_source));
        else
            ds_msgbox('Message', ...
                {'An S-function source file for floating-point simulation', ...
                ['''' sfcn_source ''''], ...
                'could not be found.'},'Title','File not found','Style','Error');
        end

    case 'ucodefileEdit'
        sfcn = tl_deblank(strtok(get(Children.ucodefileEdit,'String'),'.'),2);
        if ~ds_regexp('[a-zA-Z]+[_a-zA-Z0-9]*',[sfcn '_flp'])
            ds_msgbox('Message', ...
                'The filename must be a valid MATLAB identifier!','Title','Invalid filename','Style','Error');
        else
            dlgdata.data.codefile = tl_deblank(get(Children.ucodefileEdit,'String'),2);
            if isempty(findstr(dlgdata.data.codefile, '.'))
                dlgdata.data.codefile = [sfcn '.c'];
            end
        end
        bModified = 1;

    case 'browseButton'
        [codefile,path] = uigetfile('*.c','Custom Code files');
        if ischar(codefile)
            % check if this file is on MATLAB's search path

            fileonPath = which(codefile);
            if isempty(fileonPath)
                ds_error_msg({ ...
                    'The file', ...
                    ['   ' fullfile(path,codefile)], ...
                    'does not reside on MATLAB''s search path!'}, ...
                    'Title','File not on search path', ...
                    'MessageType','Warning','MessageNumber',1009);
            elseif ~strcmpi(fileonPath,fullfile(path,codefile))
                p = fileparts(fileonPath);
                ds_error_msg({ ...
                    'The file', ...
                    ['   ' fullfile(path,codefile)], ...
                    'resides on MATLAB''s search path,' ...
                    'but there is another file with the same name in', ...
                    ['   ' p ' .'], ...
                    'This file will hide the file you have just selected', ...
                    'when code is being generated.'}, ...
                    'Title','File hidden by another file', ...
                    'MessageType','Warning','MessageNumber',1010);
            end

            dlgdata.data.codefile = codefile;
            bModified = 1;
        end

    case 'stepsizeEdit'
        dlgdata.data.dt = get(Children.stepsizeEdit, 'String');
        bModified = 1;

    case 'flpCheckbox'
        dlgdata.data.prodcode = get(Children.flpCheckbox, 'Value');
        bModified = 1;

    case 'outputToLogPopup'
        dlgdata.currentSignal = get(Children.outputToLogPopup, 'Value');
        dlgdata.signalName = dlgdata.data.output(dlgdata.currentSignal).varname;
        bModified = 1;

    otherwise
        dlgdata.signalName = dlgdata.data.output(get(Children.outputToLogPopup, 'Value')).varname;
        [dlgdata, bModified] = ...
            TLManageLoggingCtrls('manage', pageNum, dlgdata, pageAction, 'logdata');

end


%--------------------------------------------------------------------------
% FcnUpdateCodePage updates the controls of the code & logging tab
%
% INPUT ARGUMENTS
%   dlgdata     dialog data
%   dlgfig      figure handle of dialog
%   pageNum     page Number
%
% OUTPUT ARGUMENTS
%   dlgdata     modified dialog data
%--------------------------------------------------------------------------
function dlgdata = FcnUpdateCodePage(dlgdata, dlgfig, pageNum)

% custom code option are always avaiable, independend from blockset mode
stepsizeEditCtrlStatus = struct('enable', 'on');
flpCheckboxCtrlStatus = struct('enable', 'on');
ucodefileEditCtrlStatus = struct('enable', 'on');

stepsizeEditCtrlStatus.string = dlgdata.data.dt;
flpCheckboxCtrlStatus.value = dlgdata.data.prodcode;
ucodefileEditCtrlStatus.string = dlgdata.data.codefile;

Children = dlgdata.pageData{pageNum}.children;

if isfield(dlgdata.data, 'output')
    if ~isfield(dlgdata, 'signalName') || isempty(find(strcmp({dlgdata.data.output.varname},dlgdata.signalName) == 1, 1))
        % current signal is not an output; set currentSignal to old value
        dlgdata.currentSignal = min([get(Children.outputToLogPopup, 'Value'), numel(dlgdata.data.output)]);
    end
    % default control status
    if dlgdata.bIsFullVs
        defaultStatus = 'on';
    else
        defaultStatus = 'inactive';
    end
    outputToLogPopupCtrlStatus = struct('enable', defaultStatus);
    outputToLogPopupCtrlStatus.string = {dlgdata.data.output.varname};
    outputToLogPopupCtrlStatus.value = dlgdata.currentSignal;
else
    outputToLogPopupCtrlStatus = struct('enable', 'off', ...
        'string',   ' ', ...
        'value',    1); %#ok
end

ctrlsList = {'stepsizeEdit', 'flpCheckbox', 'ucodefileEdit', 'outputToLogPopup'};
for ctrlsNo=1:length(ctrlsList)
    ctrl = Children.(ctrlsList{ctrlsNo});
    UserData = get(ctrl, 'UserData');
    UserData.ctrlStatus = eval([ctrlsList{ctrlsNo} 'CtrlStatus']);
    set(ctrl, 'UserData', UserData);
end
TLSetCtrlsStatus(dlgfig, Children, ctrlsList)

dlgdata =  TLManageLoggingCtrls('update',pageNum,dlgdata,'logdata','output');
TLManageLoggingCtrls('setCtrls',pageNum, dlgfig, dlgdata);
